home *** CD-ROM | disk | FTP | other *** search
- TITLE WalkTree - Execute Program at Every Level of Tree
-
- ; Copyright Notice:
- ;
- ; The program WalkTree, both in binary executable and source forms, is
- ; in the public domain. No warranty is given or implied, and no
- ; liability will be assumed by the author.
- ;
- ; Everyone on earth is hereby given permission to use, copy, distribute,
- ; change, mangle, destroy or otherwise employ these programs, in whole
- ; or in part, in any fashion they so desire, provided they hurt no one
- ; but themselves in the process.
- ;
- ; If anyone has any questions about this or any other program that I
- ; have authored, I can be reached by messages on any of the following
- ; systems:
- ;
- ; Bob's Answering Machine (602) 242-3158 300/1200 bps
- ; FIDO 114/1 Phoenix Node (602) 242-5230 300/1200/2400 bps
- ; FIDO 114/446 XTRA #1 (602) 979-6352 300/1200/2400 bps
- ; Technoids Anonymous (602) 899-4876 300/1200/2400 bps
- ;
- ; All excellent 24 hour systems.
- ;
- ; Don A. Williams
- ; 3913 W. Solano Dr. N.
- ; Phoenix, AZ 85019
-
-
- ; This version of the source for WalkTree has been set up for assembly by
- ; SpeedWare's very good TurboEditAsm. To convert it for assembly by
- ; Microsoft's MASM will require the addition of Segment and Assume
- ; statements, at least.
- ;
- ;
- ; version history
- ; modified by John Covici
- ; 3 Wirt Street NW
- ; Leesburg, VA 22075
- ; March 12, 1987 fixed the following bugs:
- ; (1) append cr to generated command line (if not dos goes out to lunch)
- ; (2) now assembles with masm
- ; (3) to get environment segment had to say [ds:2ch] instead of [2ch]
- ; otherwise assembler ignored brackets without error
-
- LF EQU 0AH ; ASCII Line Feed
- CR EQU 0DH ; ASCII Carriage Return
-
-
- cseg segment para public 'code'
- ORG 0100H
- assume cs:cseg,ds:cseg,ss:cseg
- Start: jmp Begin ; Jump over data area
-
- ;------ Messages
-
- LogOn db 'WalkTree: Version 1.01 - March 12, 1987',CR,LF,LF,'$'
-
- BadVer db 'WalkTree requires Dos 2.0 or greater',CR,LF,'$'
-
- UseMsg db 'USAGE: WalkTree <any dos command>',CR,LF,'$'
-
- EndMs1 db CR,LF,'Number of directories= $'
- EndMs2 db ': Maximum depth= $'
- EndMsg db '$'
-
- AbtMsg db 'Program terminated by operator.',CR,LF,'$'
-
- ;------ Constants and Other Data Storage
-
- Path db 0,':\',65 DUP(0)
-
- PatMsg db CR,LF,LF,'---'
- CurPat db 0,':\',65 DUP(0)
- PatTer db '---',CR,LF,0
-
-
- MatAll db '*.*',0
-
- Parent db '..',0
-
- CmdTail db 0,'/c '
- CmdLin db 128 DUP(0)
-
- ComSpc db 'COMSPEC',0
-
- ComCom db '\COMMAND.COM',0
-
- DTAOfs dw 0 ; Save space for DTA: Offset and
- DTASeg dw 0 ; ... Segment
-
- SaveSS dw 0 ; Save space for Stack; Segment and
- SaveSP dw 0 ; ... Pointer
-
- Level dw 0 ; Current depth in hierarchy
- MaxLev dw 0 ; Maximum depth in hierarchy
-
- DirCnt dw 0 ; Count of directories processed
- comand db 65 dup(0) ;space for command.com from env or default
-
- ;------ Parameter Block for DOS function 4B, Exec
-
- ParBlk dw 0 ; Seg of environment string
- dw 0 ; Ofs of Command Tail string
- dw 0 ; Seg " " " "
- dw 0 ; Ofs of Default FCB 1
- dw 0 ; Seg " " " "
- dw 0 ; Ofs of Default FCB 2
- dw 0 ; Seg " " " "
-
- ;=========================================================================
- ; Beginning of Program Code
-
- Begin: mov SP,offset STACK ; Set local stack
- cld ; Clear Direction Flag [forward]
- mov DX,offset LogOn ; Dsiplay logon message
- mov AH,9 ; ... MS-DOS 'Print String'
- int 21H ; ... DOS Entry Interrupt
- mov AH,30H ; MS-DOS 'Get Version'
- int 21H ; ... DOS Entry Interrupt
- cmp AL,2 ; Check for 2.x or greater
- jnb VerOk ; ... Xfr- 2.x or greater
- mov DX,offset BadVer ; Get ptr to 'bad version' msg
- ErrorExit:
- mov AH,9 ; MS-DOS 'Print String'
- int 21H ; ... DOS Entry Interrupt
- int 20H ; DOS Terminate Program Interrupt
-
- VerOk: mov AH,19H ; MS-DOS 'Get Current Disk'
- int 21H ; ... DOS Entry Interrupt
- add AL,'A' ; Convert disk code to alpha disk
- mov Path,AL ; ... and save in Path
- mov CurPat,AL ; ... and in Current Path
- mov SI,offset Path+3 ; Get Current Dir as starting path
- mov DL,0 ; ... current disk
- mov AH,47H ; ... MS-DOS 'Get Current Directory'
- int 21H ; ... DOS Entry Interrupt
- mov SI,80H ; Get ptr to Command Line buffer
- lodsb ; ... and get length
- or AL,AL ; Check for length zero - no tail
- jnz HaveTail ; ... Xfr - length not zero
- Usage:
- mov DX,offset UseMsg ; Display 'Usage' message and
- jmp short ErrorExit ; ... terminate
-
- HaveTail:
- cbw ; Make length 16 bits
- mov CX,AX ; ... and move to CX for move
- add AL,3 ; Adjust length for '/c '
- mov CmdTail,AL ; ... and store for DOS 4BH
- mov DI,offset CmdLin ; Get ptr to internal Cmnd Line
- repz movsb ; Move command line to internal store
- mov byte ptr[di],0dh ;append carriage return
- mov BX,1000H ; Release all but 1000H paragraphs
- mov AH,4AH ; ... MS-DOS 'Modify Allocated Memory'
- int 21H ; ... DOS Entry Interrupt
- call WalkTree ; Walk the tree recursively
- mov DX,offset EndMs1 ; Print out run statistics
- mov AH,9 ; ... MS-DOS 'Print String'
- int 21H ; ... DOS Entry Interrupt
- mov BX,DirCnt ; Display directory count in
- call PrintDecimal ; ... decimal
- mov DX,offset EndMs2 ; Display 2nd part of message
- mov AH,9 ; ... MS-DOS 'Print String'
- int 21H ; ... DOS Entry Interrupt
- mov BX,MaxLev ; Display maximum level in
- call PrintDecimal ; ... decimal
- mov DX,offset EndMsg ; Get ptr final part of message
- Terminate:
- mov AH,9 ; MS-DOS 'Print String'
- int 21H ; ... DOS Entry Interrupt
- mov DX,offset Path ; Restore directory to starting
- mov AH,3BH ; ... MS-DOS 'Change Subdirectory'
- int 21H ; ... DOS Entry Interrupt
- int 20H ; DOS Terminate Program
-
- ;=========================================================================
- ; WalkTree is a recursive subroutine that processes each level of the
- ; directory hierarchy. Each invocation of Walktree creates and uses a
- ; 50 byte stack frame containing the Segment and Offset of the prior
- ; level's DTA, the name of the current subdirectory, and a pointer to its
- ; own stack frame.
-
- WalkTree:
- mov SI,offset CurPat+3 ; Get current directory name
- mov DL,0 ; ... current disk
- mov AH,47H ; ... MS-DOS 'Get Current Directory'
- int 21H ; ... DOS Entry Interrupt
- mov SI,offset PatMsg ; Display Current directory
- call PrintString ; ...
- mov SI,offset PatTer ; Terminate Current directory
- call PrintString ; ...
- inc DirCnt ; Incr count of directories
- mov AX,Level ; Incr level
- inc AX ; ...
- mov Level,AX ; ... and store updated value
- cmp AX,MaxLev ; Update Maximum level, if necessary
- jbe WT1 ; ... Xfr - not necessary
- mov MaxLev,AX ; ...
- WT1: push BP ; Save old stack frame ptr
- sub SP,49 ; ... and get new stack frame
- mov BP,SP ; ...
- add BP,4 ; ... leave room for DTA adr
- push ES ; Save ES over DOS call
- mov AH,2FH ; MS-DOS 'Get DTA'
- int 21H ; DOS Entry Interrupt
- mov [BP-4],BX ; Save DTA offset and DTA segment
- mov [BP-2],ES ; ... in stack frame
- pop ES ; Restore saved ES
- mov DX,BP ; Set DTA to Stack frame
- mov AH,1AH ; ... MS-DOS 'Set DTA'
- int 21H ; ... DOS Entry Interrupt
- call CheckAbort ; Check for operator abort
- call Execute
- mov DX,offset MatAll ; Get ptr to ALL match string
- mov CX,10H ; ... set attribute for Subdirectory
- mov AH,4EH ; ... MS-DOS 'Find 1st Match'
- int 21H ; ... DOS Entry Interrupt
- jb PopLevel ; ... Xfr - Had error
- ProcessSub:
- test byte ptr [BP+21],10H ; Check for Subdirectory
- jz GetNextSub ; ... Xfr - not Subdirectory
- cmp byte ptr [BP+30],'.' ; Check for 'parent' or 'self' entries
- jz GetNextSub ; ... Xfr - 'parent' or 'self'
- mov DX,BP ; Get ptr to DTA
- add DX,30 ; ... and compute name ptr
- mov AH,3BH ; MS-DOS 'Change SubDirectory'
- int 21H ; ... DOS Entry Interrupt
- call CheckAbort ; Check for operator abort
- call WalkTree ; Walk the tree of new directory
- GetNextSub:
- mov AH,4FH ; MS-DOS 'Find Next Match'
- mov CX,10H ; ... set attribute for directory
- int 21H ; ... DOS Entry Interrupt
- jb PopLevel ; ... Xfr - error - no more matches
- jmp short ProcessSub ; Loop through directory
-
- PopLevel:
- mov DX,offset Parent ; Get ptr to 'Parent' string
- mov AH,3BH ; ... MS-DOS 'Change SubDirectory'
- int 21H ; ... DOS Entry Interrupt
- push DS ; Save DS
- mov DS,[BP-2] ; Restore prior DTA from stack
- mov DX,[BP-4] ; ... frame
- mov AH,1AH ; MS-DOS 'Set DTA'
- int 21H ; ... DOS Entry Interrupt
- pop DS ; Restore saved DS
- dec Level ; Decr directory level count
- add SP,49 ; Delete stack frame
- pop BP ; Restore stack frame ptr
- ret
-
- ; End of WalkTree
- ;-------------------------------------------------------------------------
-
- ;=========================================================================
- ; CheckAbort is used to check for an Operator Abort [any key pressed
- ; during execution.
-
- CheckAbort:
- mov AH,0BH ; MS-DOS 'Check StdIn Status'
- int 21H ; ... DOS Entry Interrupt
- or AL,AL ; Check for Char ready
- jz CAExit ; ... Xfr - no char ready
- mov AH,08H ; MS-DOS 'Console In, No Echo'
- int 21H ; ... DOS Entry Interrupt
- mov DX,offset AbtMsg ; Get ptr to 'abort' message
- jmp Terminate ; ... and terminate program
-
- CAExit: ret
-
- ; End of CheckAbort
- ;-------------------------------------------------------------------------
-
- ;=========================================================================
- ; Execute is used to execute the program specified on WalkTree's Command
- ; line. It uses MS-DOS Function 21H, SubFunction 4BH [Exec] to execute
- ; COMMAND.COM as a child. It searches the Environment to find COMSPEC
- ; in order to call COMMAND.COM
-
- Execute:
- push BP ; Save caller's registers
- push DS ; ...
- push ES ; ...
- push ES ; Save ES over CALL
- mov AH,2FH ; MS-DOS 'Get DTA'
- int 21H ; ... DOS Entry Interrupt
- mov DTASeg,ES ; Save DTA segment
- mov DTAOfs,BX ; ... and Offset
- pop ES ; Restore saved ES
- mov AX,CS ; Get segment for DOS 4B
- mov ParBlk+4,AX ; ... and store as Command Tail Seg
- mov ParBlk+8,AX ; ... and as FCB 1 Seg
- mov ParBlk+12,AX ; ... and as FCB 2 Seg
- mov ParBlk+2,offset CmdTail ; Store offset of Cmnd Tail
- mov ParBlk+6,5CH ; ... and offset of FCB 1
- mov ParBlk+10,6CH ; ... and offset of FCB 2
- mov DI,offset ComSpc
- mov bx,[ds:2ch] ;get environment string segment
- mov ParBlk,BX ; ... to Parameter Blk for DOS 4BH
- call FindComSpec ; Search environment for COMSPEC
- jnc GotComSpec ; ... Xfr - found COMSPEC
- mov AX,CS ; Set DS to local data space
- mov DS,AX ; ...
- mov dx, offset ComCom ;get ptr to 'command.com'
- jmp short goexec
- GotComSpec:
- mov di,offset comand ; dest offset of comand in di
- mov cl,65;large enough number
- smov1:
- lodsb ;load byte in al
- stosb ;store byte in comand
- or al,al
- loopnz smov1
- mov AX,CS ; Set DS to local data space
- mov DS,AX ; ...
- mov dx,offset comand;file name to execute
- goexec:
- mov BX,offset ParBlk ; Get ptr to Parameter Block for DOS 4BH
- mov CS:SaveSS,SS ; Save Stack Segment & offset over
- mov CS:SaveSP,SP ; ... Exec call
- mov AX,4B00H ; MS-DOS 'Load & Execute Program'
- int 21H ; ... DOS Entry Interrupt
- cli ; Inhibit interrupts
- mov SS,CS:SaveSS ; Restore Stack Segment &
- mov SP,CS:SaveSP ; ... Offset
- sti ; Enable interrupts
- mov DS,CS:DTASeg ; Restore local data space
- mov DX,CS:DTAOfs
- mov AH,1AH ; MS-DOS 'Set DTA'
- int 21H ; ... DOS Entry Interrupt
- pop ES
- pop DS
- pop BP
- ret
-
- ; End of Execute
- ;-------------------------------------------------------------------------
-
- ;=========================================================================
- ; FindComSpec is used by Execute to locate COMSPEC in the Environment and
- ; the name of COMMAND.COM to pass to MS-DOS 21H, SubFunction 4B [Exec].
-
- FindComSpec:
- mov DS,BX ; Set data space to Environment
- mov DI,offset ComSpc ; Get ptr to 'COMSPEC' for search
- sub SI,SI ; Start at relative 0 in Environment
- mov CX,7 ; Get length of 'COMSPEC'
-
- XFCS3: lodsb ; Get byte from Environment
- or AL,AL ; Check for end of entry
- jnz XFCS4 ; ... Xfr - not end of entry
- cmp byte ptr [SI+1],0 ; Check for end of Environment
- jz XFCS5 ; ... Xfr - end of Environment
- XFCS4: call UpCase ; Convert to upper case and
- mov [SI-1],AL ; ... store back in Environment
- cmp AL,'=' ; Check for '=' as in 'COMSPEC='
- jnz XFCS3 ; ... Xfr - not '='
- push SI ; Save both ptrs and length
- push DI ; ...
- push CX ; ...
- sub SI,2 ; Back up SI to end of string
- std ; Set Direction Flag [reverse]
- repnz cmpsb ; Compare Envirn string to 'COMSPEC'
- cld ; Clear Direction Flag [forward]
- pop CX ; Restore length and both ptrs
- pop DI ; ...
- pop SI ; ...
- jnz XFCS3 ; Xfr - did not match 'COMSPEC'
- clc ; Clear CARRY for good return
- ret
-
- XFCS5: stc ; Set CARRY for error return
- ret
-
- ; End of FindComSpec
- ;-------------------------------------------------------------------------
-
- ;=========================================================================
- ; UpCase is a utility subroutine to convert the lower case alpha char in
- ; AL to upper case. Only lower case alphas are affected, any other char
- ; in AL is returned unmodified.
-
- UpCase: cmp AL,'a' ; Check upper bound of lower case
- jb UCExit ; ... Xfr - not lower case - too low
- cmp AL,'z' ; Check upper bound of lower case
- ja UCExit ; ... Xfr - not lower case - too high
- and AL,0DFH ; Convert char to upper case
- UCExit: ret
-
- ;End of UpCase
- ;-------------------------------------------------------------------------
-
- ;=========================================================================
- ; PrintDecimal is a utility subroutine used to convert the 16-bit integer
- ; in BX to decimal and display it on StdOut as a 5-digit figure with
- ; blank suppression of leading zeros. It is overkill for the current
- ; version of WalkTree.
-
- PrintDecimal:
- mov CL,0
- mov DX,10000 ; Get 10,000s digit and display
- call PrintDigit ; ... it
- mov DX,1000 ; Get 1,000s digit and display
- call PrintDigit ; ... it
- mov DX,100 ; Get 100s digit and display
- call PrintDigit ; ... it
- mov DX,10 ; Get 10s digit and display
- call PrintDigit ; ... it
- mov CH,BL ; Display units digit [no zero
- jmp short XPD2 ; ... suppression]
-
- PrintDigit:
- mov CH,0FFH ; Initialize result
- XPD1: inc CH ; Incr result
- sub BX,DX ; Divide by repetitive subtraction
- jnb XPD1 ; ... Xfr - not there yet
- add BX,DX ; Correct for overshoot
- cmp CH,0 ; Check result for zero
- jnz XPD2 ; ... Xfr - not zero result
- test CL,1 ; Test for leading zero
- jnz XPD2 ; ... Xfr - not leading zero
- ret
-
- XPD2: push DX ; Save divisor
- mov DL,CH ; Move digit to DL for DOS
- add DL,'0' ; Convert digit to ASCII
- mov AH,2 ; MS-DOS 'Console Output
- int 21H ; ... DOS ENtry Interrupt
- pop DX ; Restore divisor
- mov CL,1 ; Turn OFF zero suppression
- ret
-
- ; End of PrintDecimal
- ;-------------------------------------------------------------------------
-
- ;=========================================================================
- ; PrintString is a utility subroutine to display a NULL-terminated ASCII
- ; string on StdOut. On input, SI contains the address of the string to
- ; be displayed. All other registers are preserved.
-
- PrintString:
- push AX
- push DX
-
- PS1: lodsb
- or AL,AL
- jz PSExit
- mov DL,AL
- mov AH,02H
- int 21H
- jmp short PS1
-
- PSExit: pop DX
- pop AX
- ret
-
- ;End of PrintString
- ;-------------------------------------------------------------------------
-
- ;=========================================================================
- ; Stack space. Since each invocation of the WalkTree subroutine creates a
- ; 50 byte stack frame on this stack, 3000 bytes of stack would allow for
- ; approximately 60 levels in the directory hierarchy, probably extreme
- ; overkill.
-
- STACK EQU $+3000
-
- cseg ends
- end Start
-